package com.linln.admin.app.controller;

import com.linln.admin.app.constants.AppConstants;
import com.linln.admin.app.domain.AppInfo;
import com.linln.admin.app.domain.AppVersion;
import com.linln.admin.app.domain.VersionApp;
import com.linln.admin.app.service.InfoService;
import com.linln.admin.app.service.VersionAppService;
import com.linln.admin.app.service.VersionService;
import com.linln.admin.system.service.TaskQueueService;
import com.linln.common.utils.ResultVoUtil;
import com.linln.common.vo.ResultVo;
import com.linln.component.actionLog.annotation.ActionLog;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author taofucheng
 * @date 2021/07/11
 */
@Slf4j
@Controller
@RequestMapping("/app/versionApp")
public class VersionAppController {

    @Autowired
    private VersionAppService versionAppService;
    @Autowired
    private InfoService infoService;
    @Autowired
    private VersionService versionService;
    @Autowired
    private TaskQueueService taskQueueService;

    /**
     * 已经关联的所有的应用项目列表
     */
    @PostMapping("/index")
    @RequiresPermissions("app:versionApp:index")
    public String index(VersionApp versionApp, Model model) {
        if (versionApp.getVersion_id() == null) {
            throw new IllegalArgumentException("版本参数不正确！");
        }

        // 创建匹配器，进行动态查询匹配
        ExampleMatcher matcher = ExampleMatcher.matching();

        // 获取数据列表
        Example<VersionApp> example = Example.of(versionApp, matcher);
        Page<VersionApp> list = versionAppService.getPageList(example);

        List<AppInfo> apps = infoService.getAll();
        Map<String, String> appMap = new HashMap<>();
        if (apps != null) {
            for (AppInfo app : apps) {
                appMap.put(app.getId() + "", app.getDisplay_name());
                appMap.put(app.getId() + "_repo", FilenameUtils.getBaseName(app.getRepo_url()));
            }
        }

        // 封装数据
        model.addAttribute("list", list.getContent());
        model.addAttribute("page", list);
        model.addAttribute("appMap", appMap);
        model.addAttribute("appVersion", versionService.getById(versionApp.getVersion_id()));
        return "/app/versionApp/index";
    }

    /**
     * 获取所有项目列表
     */
    @GetMapping("/allapps")
    @RequiresPermissions("app:versionApp:allapps")
    public String allApps(String versionId, Model model) {
        //获取所有可选择的项目，并回显哪些已经选择过的。
        Page<AppInfo> list = infoService.getAllWithPage(5000);

        List<Long> selectedList = new ArrayList<>();
        VersionApp wa = new VersionApp();
        wa.setVersion_id(Long.parseLong(versionId));
        Page<VersionApp> selected = versionAppService.getPageList(Example.of(wa));
        if (selected.hasContent()) {
            for (VersionApp va : selected) {
                selectedList.add(va.getApp_id());
            }
        }
        // 封装数据
        model.addAttribute("list", list.getContent());
        model.addAttribute("page", list);
        model.addAttribute("versionId", versionId);

        model.addAttribute("selectedList", selectedList);
        return "/app/versionApp/allapps";
    }

    /**
     * 保存添加/修改的数据，将关联数据保存下来。
     *
     * @param versionId 对应的版本id
     * @param ids       选中的项目id
     * @return
     */
    @PostMapping("/save")
    @RequiresPermissions({"app:versionApp:save"})
    @ResponseBody
    @ActionLog(name = "版本分支管理", message = "绑定版本[${versionId}]中所需要的应用[${ids}]，并切分支")
    public ResultVo saveRelatedApps(String versionId, String[] ids) {
        try {
            return ResultVoUtil.success("保存成功！", versionAppService.saveRelatedApps(versionId, ids));
        } catch (Exception e) {
            return ResultVoUtil.error("保存失败！");
        }
    }

    /**
     * 当前任务的状态
     *
     * @param versionId
     * @return
     */
    @RequestMapping("/task/status")
    @ResponseBody
    public ResultVo getTaskStatus(String versionId) {
        try {
            return ResultVoUtil.success("获取成功！", taskQueueService.getOneTodoDescriptByRelatedId(Long.parseLong(versionId)));
        } catch (Exception e) {
            return ResultVoUtil.error("获取失败！");
        }
    }

    /**
     * 检查代码规范的结果
     *
     * @param versionId
     * @return
     */
    @RequestMapping("/task/pmdres")
    @ResponseBody
    public ResultVo getTaskPmdRes(String versionId) {
        try {
            return ResultVoUtil.success("获取成功！", taskQueueService.getLastPmdCheckResultByRelatedId(Long.parseLong(versionId)));
        } catch (Exception e) {
            return ResultVoUtil.error("获取失败！");
        }
    }

    /**
     * 清空检查结果，下次不再显示
     *
     * @param versionId
     * @return
     */
    @RequestMapping("/task/pmdresclear")
    @ResponseBody
    public ResultVo clearTaskPmdRes(String versionId) {
        try {
            return ResultVoUtil.success("操作成功！", taskQueueService.clearLastPmdCheckResultByRelatedId(Long.parseLong(versionId)));
        } catch (Exception e) {
            return ResultVoUtil.error("操作失败！");
        }
    }

    /**
     * 指定哪些项目合并代码到release分支
     *
     * @param versionId 主键ID
     * @param ids       选中的项目的id
     * @return
     */
    @PostMapping("/branch/merge2release")
    @RequiresPermissions({"app:versionApp:branch:merge2release"})
    @ResponseBody
    @ActionLog(name = "版本分支管理", message = "将版本中开发分支[${versionId}]代码合并到发布分支")
    public ResultVo mergeDev2ReleaseBranch(String versionId, String[] ids) {
        try {
            Long taskId = versionAppService.mergeDev2ReleaseBranch(versionId, ids);
            versionService.branchPmdCheck(Long.parseLong(versionId));
            return ResultVoUtil.success("操作完成，请等待操作结果...", taskId);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultVoUtil.error("操作失败！");
        }
    }

    /**
     * 指定哪些项目从prod合并代码
     *
     * @param versionId 主键ID
     * @param ids       选中的项目的id
     * @return
     */
    @PostMapping("/branch/mergefromprod")
    @RequiresPermissions({"app:versionApp:branch:mergefromprod"})
    @ResponseBody
    @ActionLog(name = "版本分支管理", message = "将prod代码合并到版本中开发分支[${versionId}]")
    public ResultVo mergeProd2DevBranch(String versionId, String[] ids) {
        try {
            return ResultVoUtil.success("操作完成，请等待操作结果...", versionAppService.mergeProd2DevBranch(versionId, ids));
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResultVoUtil.error("操作失败！");
        }
    }

    /**
     * 完成手动处理冲突，即：手动确认已合并
     *
     * @param versionId 主键ID
     * @param ids       选中的项目的id
     * @return
     */
    @PostMapping("/branch/manualmerge")
    @RequiresPermissions({"app:versionApp:branch:manualmerge"})
    @ResponseBody
    @ActionLog(name = "版本分支管理", message = "将版本[${versionId}]冲突的应用手动标记为已解决")
    public ResultVo manualMergeBranch(String versionId, String[] ids) {
        try {
            ResultVo ret = ResultVoUtil.success("操作成功！", versionAppService.manualMergeBranch(versionId, ids));
            versionAppService.mergeProd2DevBranch(versionId, ids);//手动确认已经合并后，强制从prod合并一下，确保手动操作的正确性。
            return ret;
        } catch (Exception e) {
            return ResultVoUtil.error("操作失败！");
        }
    }


    /**
     * 将指定的项目deploy
     *
     * @param versionId 主键ID
     * @param ids       选中的项目的id
     * @return
     */
    @PostMapping("/branch/deploy")
    @RequiresPermissions({"app:versionApp:branch:deploy"})
    @ResponseBody
    @ActionLog(name = "版本分支管理", message = "将版本中开发分支[${versionId}]中的应用[${ids}]进行mvn deploy打包")
    public ResultVo deploy(String versionId, String[] ids) {
        try {
            //如果当前应用是hotfix版本，强制先进行校验
            AppVersion ver = versionService.getById(Long.parseLong(versionId));
            if (AppConstants.YES.equals(ver.getHotfix_flag())) {
                versionService.branchPmdCheck(Long.parseLong(versionId));
            }
            //再进行打包操作
            return ResultVoUtil.success("操作成功！", versionAppService.deploy(versionId, ids));
        } catch (Exception e) {
            return ResultVoUtil.error("操作失败！" + e.getMessage());
        }
    }
}